#!/usr/bin/env tclsh

set testdir [file dirname $argv0]
source $testdir/tester.tcl

do_execsql_test date-current-date {
  SELECT length(date('now')) = 10;
} {1}

do_execsql_test date-specific-date {
  SELECT date('2023-05-18');
} {2023-05-18}

do_execsql_test date-with-time {
  SELECT date('2023-05-18 15:30:45');
} {2023-05-18}

do_execsql_test date-iso8601 {
  SELECT date('2023-05-18T15:30:45');
} {2023-05-18}

do_execsql_test date-with-milliseconds {
  SELECT date('2023-05-18 15:30:45.123');
} {2023-05-18}

do_execsql_test date-julian-day-integer {
  SELECT date(2460082);
} {2023-05-17}

do_execsql_test date-julian-day-float {
  SELECT date(2460082.5);
} {2023-05-18}

do_execsql_test date-invalid-input {
  SELECT date('not a date');
} {{}}

do_execsql_test date-null-input {
  SELECT date(NULL);
} {{}}

do_execsql_test date-out-of-range {
  SELECT date('10001-01-01');
} {{}}

do_execsql_test date-time-only {
  SELECT date('15:30:45');
} {2000-01-01}

do_execsql_test date-with-timezone-utc {
  SELECT date('2023-05-18 15:30:45Z');
} {2023-05-18}

do_execsql_test date-with-timezone-positive {
  SELECT date('2023-05-18 23:30:45+02:00');
} {2023-05-18}

do_execsql_test date-with-timezone-negative {
  SELECT date('2023-05-19 01:30:45-05:00');
} {2023-05-19}

do_execsql_test date-with-timezone-day-change-positive {
  SELECT date('2023-05-18 23:30:45-03:00');
} {2023-05-19}

do_execsql_test date-with-timezone-day-change-negative {
  SELECT date('2023-05-19 01:30:45+03:00');
} {2023-05-18}

do_execsql_test date-with-timezone-iso8601 {
  SELECT date('2023-05-18T15:30:45+02:00');
} {2023-05-18}

do_execsql_test date-with-timezone-and-milliseconds {
  SELECT date('2023-05-18 15:30:45.123+02:00');
} {2023-05-18}

do_execsql_test date-with-invalid-timezone {
  SELECT date('2023-05-18 15:30:45+25:00');
} {{}}

do_execsql_test date-with-modifier-add-days {
  SELECT date('2023-05-18', '+10 days');
} {2023-05-28}

do_execsql_test date-with-modifier-subtract-days {
  SELECT date('2023-05-18', '-10 days');
} {2023-05-08}

do_execsql_test date-with-multiple-modifiers {
  SELECT date('2023-05-18', '+1 days', '-1 days', '+10 days');
} {2023-05-28}

do_execsql_test date-with-invalid-modifier {
  SELECT date('2023-05-18', 'invalid modifier');
} {{}}

do_execsql_test time-no-arg {
  SELECT length(time()) = 8;
} {1}

do_execsql_test time-current-time {
  SELECT length(time('now')) = 8;
} {1}

do_execsql_test time-specific-time {
  SELECT time('04:02:00');
} {04:02:00}

do_execsql_test time-of-datetime {
  SELECT time('2023-05-18 15:30:45');
} {15:30:45}

do_execsql_test time-iso8601 {
  SELECT time('2023-05-18T15:30:45');
} {15:30:45}

do_execsql_test time-with-milliseconds {
  SELECT time('2023-05-18 15:30:45.123');
} {15:30:45}

do_execsql_test time-julian-day-integer {
  SELECT time(2460082);
} {12:00:00}

do_execsql_test time-julian-day-float {
  SELECT time(2460082.2);
} {16:48:00}

do_execsql_test time-invalid-input {
  SELECT time('not a time');
} {{}}

do_execsql_test time-null-input {
  SELECT time(NULL);
} {{}}

do_execsql_test time-out-of-range {
  SELECT time('25:05:01');
} {{}}

do_execsql_test time-date-only {
  SELECT time('2024-02-02');
} {00:00:00}

do_execsql_test time-with-timezone-utc {
  SELECT time('2023-05-18 15:30:45Z');
} {15:30:45}

do_execsql_test time-with-timezone-positive {
  SELECT time('2023-05-18 23:30:45+07:00');
} {16:30:45}

do_execsql_test time-with-timezone-negative {
  SELECT time('2023-05-19 01:30:45-05:00');
} {06:30:45}

do_execsql_test time-with-timezone-day-change-positive {
  SELECT time('2023-05-18 23:30:45-03:00');
} {02:30:45}

do_execsql_test time-with-timezone-day-change-negative {
  SELECT time('2023-05-19 01:30:45+03:00');
} {22:30:45}

do_execsql_test time-with-timezone-iso8601 {
  SELECT time('2023-05-18T15:30:45+02:00');
} {13:30:45}

do_execsql_test time-with-timezone-and-milliseconds {
  SELECT time('2023-05-18 15:30:45.123+02:00');
} {13:30:45}

do_execsql_test time-with-invalid-timezone {
  SELECT time('2023-05-18 15:30:45+25:00');
} {{}}

do_execsql_test time-with-modifier-start-of-day {
  SELECT time('2023-05-18 15:30:45', 'start of day');
} {00:00:00}

do_execsql_test time-with-modifier-add-hours {
  SELECT time('2023-05-18 15:30:45', '+2 hours');
} {17:30:45}

do_execsql_test time-with-modifier-add-minutes {
  SELECT time('2023-05-18 15:30:45', '+45 minutes');
} {16:15:45}

do_execsql_test time-with-modifier-add-seconds {
  SELECT time('2023-05-18 15:30:45', '+30 seconds');
} {15:31:15}

do_execsql_test time-with-modifier-subtract-hours {
  SELECT time('2023-05-18 15:30:45', '-3 hours');
} {12:30:45}

do_execsql_test time-with-modifier-subtract-minutes {
  SELECT time('2023-05-18 15:30:45', '-15 minutes');
} {15:15:45}

do_execsql_test time-with-modifier-subtract-seconds {
  SELECT time('2023-05-18 15:30:45', '-45 seconds');
} {15:30:00}

do_execsql_test time-with-multiple-modifiers {
  SELECT time('2023-05-18 15:30:45', '+1 hours', '-30 minutes', '+15 seconds');
} {16:01:00}

do_execsql_test time-with-invalid-modifier {
  SELECT time('2023-05-18 15:30:45', 'invalid modifier');
} {{}}

do_execsql_test time-with-invalid-modifier {
  SELECT time('2023-05-18 15:30:45', '+1 hour', 'invalid modifier');
} {{}}

do_execsql_test unixepoch-at-start {
  SELECT unixepoch('1970-01-01');
} {0}

do_execsql_test unixepoch-at-1-second-before-epochtime {
  SELECT unixepoch('1969-12-31 23:59:59');
} {-1}

do_execsql_test unixepoch-at-future {
  SELECT unixepoch('9999-12-31 23:59:59');
} {253402300799}

do_execsql_test unixepoch-at-start-of-time {
  SELECT unixepoch('0000-01-01 00:00:00');
} {-62167219200}

do_execsql_test unixepoch-at-millisecond-precision-input-produces-seconds-precision-output {
  SELECT unixepoch('2022-01-27 12:59:28.052');
} {1643288368}

do_execsql_test date-with-modifier-start-of-day {
  SELECT date('2023-05-18 15:30:45', 'start of day');
} {2023-05-18}

do_execsql_test date-with-modifier-start-of-month {
  SELECT date('2023-05-18', 'start of month');
} {2023-05-01}

do_execsql_test date-with-modifier-start-of-year {
  SELECT date('2023-05-18', 'start of year');
} {2023-01-01}

do_execsql_test date-with-modifier-add-months {
  SELECT date('2023-05-18', '+2 months');
} {2023-07-18}

do_execsql_test date-with-modifier-subtract-months {
  SELECT date('2023-05-18', '-3 months');
} {2023-02-18}

do_execsql_test date-with-modifier-add-years {
  SELECT date('2023-05-18', '+1 year');
} {2024-05-18}

do_execsql_test date-with-modifier-subtract-years {
  SELECT date('2023-05-18', '-2 years');
} {2021-05-18}

do_execsql_test date-with-modifier-weekday {
  SELECT date('2023-05-18', 'weekday 0');
} {2023-05-21}

do_execsql_test date-with-multiple-modifiers {
  SELECT date('2023-05-18', '+1 month', '-10 days', 'start of year');
} {2023-01-01}

do_execsql_test date-with-subsec {
  SELECT date('2023-05-18 15:30:45.123', 'subsec');
} {2023-05-18}

do_execsql_test time-with-modifier-add-hours {
  SELECT time('2023-05-18 15:30:45', '+5 hours');
} {20:30:45}

do_execsql_test time-with-modifier-subtract-hours {
  SELECT time('2023-05-18 15:30:45', '-2 hours');
} {13:30:45}

do_execsql_test time-with-modifier-add-minutes {
  SELECT time('2023-05-18 15:30:45', '+45 minutes');
} {16:15:45}

do_execsql_test time-with-modifier-subtract-seconds {
  SELECT time('2023-05-18 15:30:45', '-50 seconds');
} {15:29:55}

do_execsql_test time-with-subsec {
  SELECT time('2023-05-18 15:30:45.123', 'subsec');
} {15:30:45.123}

do_execsql_test time-with-modifier-add {
  SELECT time('15:30:45', '+15:30:15');
} {{07:01:00}}

do_execsql_test time-with-modifier-sub {
  SELECT time('15:30:45', '-15:30:15');
} {{00:00:30}}

do_execsql_test date-with-modifier-add-months {
  SELECT date('2023-01-31', '+1 month');
} {2023-03-03}

do_execsql_test date-with-modifier-subtract-months {
  SELECT date('2023-03-31', '-1 month');
} {2023-03-03}

do_execsql_test date-with-modifier-add-months-large {
  SELECT date('2023-01-31', '+13 months');
} {2024-03-02}

do_execsql_test date-with-modifier-subtract-months-large {
  SELECT date('2023-01-31', '-13 months');
} {2021-12-31}

do_execsql_test date-with-modifier-february-leap-year {
  SELECT date('2020-02-29', '+12 months');
} {2021-03-01}

do_execsql_test date-with-modifier-february-non-leap-year {
  SELECT date('2019-02-28', '+12 months');
} {2020-02-28}

do_execsql_test date-with-modifier-invalid-date {
  SELECT date('2023-02-15 15:30:45', '-0001-01-01 00:00');
} {2022-01-14}

do_execsql_test date-with-modifier-date {
  SELECT date('2023-02-15 15:30:45', '+0001-01-01');
} {2024-03-16}

do_execsql_test datetime-with-modifier-datetime-pos {
  SELECT datetime('2023-02-15 15:30:45', '+0001-01-01 15:30');
} {{2024-03-17 07:00:45}}

do_execsql_test datetime-with-modifier-datetime-neg {
  SELECT datetime('2023-02-15 15:30:45', '+0001-01-01 15:30');
} {{2024-03-17 07:00:45}}

do_execsql_test datetime-with-modifier-datetime-large {
   SELECT datetime('2023-02-15 15:30:45', '+7777-10-10 23:59');
} {{9800-12-26 15:29:45}}

do_execsql_test datetime-with-modifier-datetime-sub-large {
   SELECT datetime('2023-02-15 15:30:45', '-2024-10-10 23:59');
} {{-0002-04-04 15:31:45}}

do_execsql_test datetime-with-timezone-utc {
  SELECT datetime('2023-05-18 15:30:45Z');
} {{2023-05-18 15:30:45}}

do_execsql_test datetime-with-modifier-sub {
   SELECT datetime('2023-12-12', '-0002-10-10 15:30:45');
} {{2021-02-01 08:29:15}}

do_execsql_test datetime-with-modifier-add {
   SELECT datetime('2023-12-12', '+0002-10-10 15:30:45');
} {{2026-10-22 15:30:45}}

do_execsql_test time-with-multiple-modifiers {
  SELECT time('2023-05-18 15:30:45', '+1 hours', '-20 minutes', '+15 seconds', 'subsec');
} {16:11:00.000}

do_execsql_test datetime-with-multiple-modifiers {
select datetime('2024-01-31', '+1 month', '+13 hours', '+5 minutes', '+62 seconds');
} {{2024-03-02 13:06:02}}

do_execsql_test datetime-with-weekday {
  SELECT datetime('2023-05-18', 'weekday 3');
} {{2023-05-24 00:00:00}}

do_execsql_test unixepoch-subsec {
  SELECT unixepoch('2023-05-18 15:30:45.123');
} {1684423845}

do_execsql_test unixepoch-invalid-date {
  SELECT unixepoch('not-a-date');
} {{}}

do_execsql_test unixepoch-leap-second {
  SELECT unixepoch('2015-06-30 23:59:60');
} {{}}

do_execsql_test unixepoch-negative-timestamp {
  SELECT unixepoch('1969-12-31 23:59:59');
} {-1}

do_execsql_test unixepoch-large-date {
  SELECT unixepoch('9999-12-31 23:59:59');
} {253402300799}

do_execsql_test datetime-with-timezone {
  SELECT datetime('2023-05-19 01:30:45+03:00');
} {{2023-05-18 22:30:45}}

do_execsql_test julianday-fractional {
    SELECT julianday('2023-05-18 15:30:45.123');
} {2460083.14635559}

do_execsql_test julianday-fractional-2 {
    SELECT julianday('2000-01-01 12:00:00.500');
} {2451545.00000579}

do_execsql_test julianday-rounded-up {
    SELECT julianday('2023-05-18 15:30:45.129');
} {2460083.14635566}

do_execsql_test julianday-with-timezone {
    SELECT julianday('2023-05-18 15:30:45+02:00');
} {2460083.06302083}

do_execsql_test julianday-fractional-seconds {
    SELECT julianday('2023-05-18 15:30:45.123');
} {2460083.14635559}

do_execsql_test julianday-time-only {
    SELECT julianday('15:30:45');
} {2451545.14635417}

#
# TODO: fix precision issue
#
#do_execsql_test julianday-midnight {
#    SELECT julianday('2023-05-18 00:00:00');
#} {2460082.5}

#do_execsql_test julianday-noon {
#    SELECT julianday('2023-05-18 12:00:00');
#} {2460083.0}

#do_execsql_test julianday-fractional-zero {
#    SELECT julianday('2023-05-18 00:00:00.000');
#} {2460082.5}

# same issue as above, we return .5000000 because we are using fmt precision
#do_execsql_test julianday-date-only {
#    SELECT julianday('2023-05-18');
#} {2460082.5}

